package oop.controller.action.test;

import java.sql.SQLException;
import java.util.List;

import oop.algorithm.BoundedSum3DRecursive;
import oop.controller.action.DefaultAction;
import oop.data.BaseQuestion;
import oop.data.LevelConstraint;
import oop.data.MarkConstraint;
import oop.data.Section;
import oop.data.SectionStructure;
import oop.data.Test;
import oop.data.TestStructure;
import oop.data.TopicConstraint;
import oop.db.dao.QuestionDAO;
import oop.db.dao.SectionDAO;
import oop.db.dao.SectionQuestionAnswerDAO;
import oop.db.dao.SectionQuestionDAO;
import oop.db.dao.TestDAO;
import oop.db.dao.TestStructureDAO;

import org.apache.commons.lang.StringUtils;

import com.oreilly.servlet.ParameterNotFoundException;

public class CreateAction extends DefaultAction {
	
	@Override
	public void performImpl() throws Exception {
		title("Tạo đề thi mới");
		String submit = request.getParameter("tc_submit");
		if ("create".equals(submit)) {
			doCreate();
		}
	}

	private void doCreate() throws SQLException {
		String name = null;
		try {
			name = getParams().getString("tc_name");
		} catch (ParameterNotFoundException ex) {
			request.setAttribute("nameErr", "Bạn cần nhập tên đề thi.");
			return;
		}
		
		String description = request.getParameter("tc_description");
		
		long topicId;
		try {
			topicId = getParams().getLong("tc_topic");
		} catch (NumberFormatException e) {
			request.setAttribute("topicErr", "Mã chủ đề không hợp lệ.");
			return;
		} catch (ParameterNotFoundException e) {
			request.setAttribute("topicErr", "Bạn cần chọn chủ đề.");
			return;
		}
		
		int time;
		try {
			time = getParams().getInt("tc_time");
		} catch (NumberFormatException e) {
			timeError = "Định dạng thời gian không hợp lệ";
			return;
		} catch (ParameterNotFoundException e) {
			timeError = "Bạn cần nhập thời gian";
			return;
		}
		
		String type;
		try {
			type = getParams().getString("tc_type");
		} catch (ParameterNotFoundException e1) {
			typeError = "Bạn cần chọn kiểu đề thi.";
			return;
		}
		
		boolean useStructure = !StringUtils.isEmpty(request
				.getParameter("tc_usestruct"));
		TestStructure structure = null;
		if (useStructure) {
			long structureId;
			try {
				structureId = getParams().getLong("tc_struct");
				structure = TestStructureDAO.fetchById(structureId).get(0);
			} catch (NumberFormatException e) {
				structError = "Mã cấu trúc đề không hợp lệ.";
				return;
			} catch (ParameterNotFoundException e) {
				structError = "Bạn cần chọn cấu trúc đề.";
				return;
			}
		}

		try {
			Test test = TestDAO.create(name, description, topicId, getUser()
					.getId(), type, time);
			if (useStructure) {
				addContent(test, structure);
			}
			setNextAction("test.view&tv_id=" + test.getId());
		} catch (SQLException e) {
			if (e.getErrorCode() == 1062) {
				request.setAttribute("nameErr", "Tên đề thi đã được sử dụng.");
				return;
			} else {
				throw e;
			}
		}
	}

	private void addContent(Test test, TestStructure structure)
			throws SQLException {
		for (SectionStructure sectionStructure : structure
				.getSectionStructures()) {
			// create section
			Section section = SectionDAO.create(sectionStructure.getText(),
					sectionStructure.getOrder(), test.getId());
			// test.addSection(section);
			// extract infos
			long[] topicIds;
			int[] topicCounts;
			if (sectionStructure.getTopicConstraints().isEmpty()) {
				topicIds = new long[] { -1 };
				topicCounts = new int[] { Integer.MAX_VALUE };
			} else {
				topicIds = new long[sectionStructure.getTopicConstraints()
						.size()];
				topicCounts = new int[sectionStructure.getTopicConstraints()
						.size()];
				for (int i = 0; i < topicIds.length; i++) {
					TopicConstraint constraint = sectionStructure
							.getTopicConstraints().get(i);
					topicIds[i] = constraint.getTopic().getId();
					topicCounts[i] = constraint.getCount();
				}
			}

			int[] levels;
			int[] levelCounts;
			if (sectionStructure.getLevelConstraints().isEmpty()) {
				levels = new int[] { -1 };
				levelCounts = new int[] { Integer.MAX_VALUE };
			} else {
				levels = new int[sectionStructure.getLevelConstraints().size()];
				levelCounts = new int[sectionStructure.getLevelConstraints()
						.size()];
				for (int i = 0; i < levels.length; i++) {
					LevelConstraint constraint = sectionStructure
							.getLevelConstraints().get(i);
					levels[i] = constraint.getLevel();
					levelCounts[i] = constraint.getCount();
				}
			}

			int[] marks;
			int[] markCounts;
			if (sectionStructure.getMarkConstraints().isEmpty()) {
				marks = new int[] { -1 };
				markCounts = new int[] { Integer.MAX_VALUE };
			} else {
				marks = new int[sectionStructure.getMarkConstraints().size()];
				markCounts = new int[sectionStructure.getMarkConstraints()
						.size()];
				for (int i = 0; i < marks.length; i++) {
					MarkConstraint constraint = sectionStructure
							.getMarkConstraints().get(i);
					marks[i] = constraint.getMark();
					markCounts[i] = constraint.getCount();
				}
			}
			// get question count
			int[][][] questionCounts = QuestionDAO.fetchCounts(test.getId(),
					topicIds, levels, marks);
			// solve
			BoundedSum3DRecursive sudoku = new BoundedSum3DRecursive(questionCounts, topicCounts,
					levelCounts, markCounts);
			for (int i = 0; i < topicIds.length; i++) {
				for (int j = 0; j < levels.length; j++) {
					for (int k = 0; k < marks.length; k++) {
						int count = sudoku.getValue(i, j, k);
						if (count > 0) {
							List<BaseQuestion> questions = QuestionDAO.fetchByInfo(section
									.getId(), levels[j], marks[k], topicIds[i],
									count);
							for (BaseQuestion question : questions) {
								SectionQuestionDAO.addQuestion(section.getId(), question.getId());
								SectionQuestionAnswerDAO.addAnswers(section.getId(), question.getId(), 4);
							}
						}
					}
				}
			}
		}
	}

	private String timeError;
	private String structError;
	private String typeError;
	
	public String getTimeError() {
		return timeError;
	}
	
	public String getStructError() {
		return structError;
	}
	
	public String getTypeError() {
		return typeError;
	}
}
